﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Formatting;
using Newtonsoft.Json.Serialization;
using Sustainalytics.Entities.ESGRatings;
using Sustainalytics.ESGRatings.DataContract.ESG;



using Xunit;
using Xunit.Abstractions;

namespace Sustainalytics.ESGComputing.Service.Tests
{
    public class ESGClientComputingMultiMatrixValidationTests : Disposable, IClassFixture<MultipleMatricesDataFixture>
    {

        private class ESGData
        {
            protected bool Equals(ESGData other)
            {
                return CompanyId.Equals(other.CompanyId) && 
                    E-other.E<=1e-16 && 
                    S-other.S<=1e-16 && 
                    G-other.G<=1e-16;;
            }

            public override bool Equals(object obj)
            {
                if (ReferenceEquals(null, obj))
                {
                    return false;
                }
                if (ReferenceEquals(this, obj))
                {
                    return true;
                }
                if (obj.GetType() != this.GetType())
                {
                    return false;
                }
                return Equals((ESGData) obj);
            }

            public override int GetHashCode()
            {
                unchecked
                {
                    var hashCode = CompanyId.GetHashCode();
                    hashCode = (hashCode*397) ^ E.GetHashCode();
                    hashCode = (hashCode*397) ^ S.GetHashCode();
                    hashCode = (hashCode*397) ^ G.GetHashCode();
                    return hashCode;
                }
            }

            public Guid CompanyId { get; set; }
            public float E { get; set; }
            public float S { get; set; }
            public float G { get; set; }

            public ESGData(Guid companyId, float e, float s, float g)
            {
                CompanyId = companyId;
                E = e;
                S = s;
                G = g;
            }

            private sealed class ESGDataEqualityComparer : IEqualityComparer<ESGData>
            {
                public bool Equals(ESGData x, ESGData y)
                {
                    return x.CompanyId.Equals(y.CompanyId) && 
                    x.E-y.E<=1e-16 && 
                    x.S-y.S<=1e-16 && 
                    x.G-y.G<=1e-16;
                }

                public int GetHashCode(ESGData obj)
                {
                    unchecked
                    {
                        var hashCode = obj.CompanyId.GetHashCode();
                        hashCode = (hashCode*397) ^ obj.E.GetHashCode();
                        hashCode = (hashCode*397) ^ obj.S.GetHashCode();
                        hashCode = (hashCode*397) ^ obj.G.GetHashCode();
                        return hashCode;
                    }
                }
            }

            private static readonly IEqualityComparer<ESGData> ESGDataComparerInstance = new ESGDataEqualityComparer();

            public static IEqualityComparer<ESGData> ESGDataComparer
            {
                get { return ESGDataComparerInstance; }
            }
        }

        private static readonly string _sutLink = "http://localhost:10280/esgcomputingserv/api/v1/esgcompute";

        private static readonly JsonMediaTypeFormatter JsonMediaTypeFormatter = new JsonMediaTypeFormatter
        {
            SerializerSettings = { ContractResolver = new CamelCasePropertyNamesContractResolver() }
        };

        private readonly MultipleMatricesDataFixture _dataFixture;
        private readonly ITestOutputHelper _output;
        private readonly HttpClient _sutClient;
        private bool _disposed;



        public ESGClientComputingMultiMatrixValidationTests(ITestOutputHelper output, MultipleMatricesDataFixture fixture)
        {
            _output = output;
            _sutClient = new HttpClient();
            _dataFixture = fixture;
        }

        ~ESGClientComputingMultiMatrixValidationTests()
        {
            Dispose(false);
        }

        [Fact]
        public void ESGComputeController_Post_Should_Return_Aggregated_Weights_Differ_For_The_Two_Matrices()
        {
            //Arrange

            var options1 = new ESGRatingsOptionsDto()
            {
                RefUnivId = _dataFixture.UniverseId,
                MatrixId = _dataFixture.Matrices[0].MatrixId,
                IncludeAggregatedScores = true,
                IncludeAggregatedWeights = true,
                IncludeIndWeightedScores = true,
                IncludeRatings = true,
                GroupBy = ComparativeGroupEnum.PeerGroup,
            };

            var options2 = new ESGRatingsOptionsDto()
            {
                RefUnivId = _dataFixture.UniverseId,
                MatrixId = _dataFixture.Matrices[1].MatrixId,
                IncludeAggregatedScores = true,
                IncludeAggregatedWeights = true,
                IncludeIndWeightedScores = true,
                IncludeRatings = true,
                GroupBy = ComparativeGroupEnum.PeerGroup,
            };

            //Act
            var result1 = _sutClient.PostAsync(_sutLink, options1, JsonMediaTypeFormatter);

            var result2 = _sutClient.PostAsync(_sutLink, options2, JsonMediaTypeFormatter);

            result1.Result.EnsureSuccessStatusCode();

            result2.Result.EnsureSuccessStatusCode();

            var esgRatingsDto = result1.Result.Content.ReadAsAsync<ESGRatingsDto>(JsonMediaTypeFormatter.Yield());

            var firstResult = esgRatingsDto.Result.Ratings.SelectMany(x => x.ClustersWeights, (companyId, companyWeights) => new { CompanyId = companyId.CompanyId, CompanyWeights = companyWeights }).ToList();

            foreach (var item in firstResult)
            {
                _output.WriteLine(item.Dump());
            }

            var secondResult = result2.Result.Content.ReadAsAsync<ESGRatingsDto>(JsonMediaTypeFormatter.Yield()).Result.Ratings.SelectMany(x => x.ClustersWeights, (companyId, companyWeights) => new { CompanyId = companyId.CompanyId, CompanyWeights = companyWeights }).ToList();

            foreach (var item in secondResult)
            {
                _output.WriteLine(item.Dump());
            }

            //Assert

            Assert.NotEqual(firstResult, secondResult);
        }

        [Fact]
        public void ESGComputeController_Post_Should_Return_Aggregated_Weights_ForMatrix_One()
        {
            //Arrange

            var options = new ESGRatingsOptionsDto()
            {
                RefUnivId = _dataFixture.UniverseId,
                MatrixId = _dataFixture.Matrices[0].MatrixId,
                IncludeAggregatedScores = true,
                IncludeAggregatedWeights = true,
                IncludeIndWeightedScores = true,
                IncludeRatings = true,
                GroupBy = ComparativeGroupEnum.PeerGroup,
            };

            //Act
            var result = _sutClient.PostAsync(_sutLink, options, JsonMediaTypeFormatter);

            result.Result.EnsureSuccessStatusCode();

            var esgRatingsDto = result.Result.Content.ReadAsAsync<ESGRatingsDto>(JsonMediaTypeFormatter.Yield());

            var items = esgRatingsDto.Result.Ratings.SelectMany(x => x.ClustersWeights, (companyId, companyWeights) => new { CompanyId = companyId.CompanyId, CompanyWeights = companyWeights }).ToList();
            foreach (var item in items)
            {
                _output.WriteLine(item.Dump());
            }

            //Assert

            Assert.True(items.All(x => x.CompanyWeights >= 0));
        }

        [Fact]
        public void ESGComputeController_Post_Should_Return_Aggregated_Weights_ForMatrix_Two()
        {
            //Arrange

            var options = new ESGRatingsOptionsDto()
            {
                RefUnivId = _dataFixture.UniverseId,
                MatrixId = _dataFixture.Matrices[1].MatrixId,
                IncludeAggregatedScores = true,
                IncludeAggregatedWeights = true,
                IncludeIndWeightedScores = true,
                IncludeRatings = true,
                GroupBy = ComparativeGroupEnum.PeerGroup,
            };

            //Act
            var result = _sutClient.PostAsync(_sutLink, options, JsonMediaTypeFormatter);

            result.Result.EnsureSuccessStatusCode();

            var esgRatingsDto = result.Result.Content.ReadAsAsync<ESGRatingsDto>(JsonMediaTypeFormatter.Yield());

            var items = esgRatingsDto.Result.Ratings.SelectMany(x => x.ClustersWeights, (companyId, companyWeights) => new { CompanyId = companyId.CompanyId, CompanyWeights = companyWeights }).ToList();
            foreach (var item in items)
            {
                _output.WriteLine(item.Dump());
            }

            //Assert

            Assert.True(items.All(x => x.CompanyWeights >= 0));
        }

        [Fact]
        public void ESGComputeController_Post_Should_Return_Aggregated_Weights_ForMatrixOne_And_Verify_if_Correct()
        {
            //Arrange

            var options1 = new ESGRatingsOptionsDto()
            {
                RefUnivId = _dataFixture.UniverseId,
                MatrixId = _dataFixture.Matrices[0].MatrixId,
                IncludeAggregatedScores = true,
                IncludeAggregatedWeights = true,
                IncludeIndWeightedScores = true,
                IncludeRatings = true,
                GroupBy = ComparativeGroupEnum.PeerGroup,
            };

            var options2 = new ESGRatingsOptionsDto()
            {
                RefUnivId = _dataFixture.UniverseId,
                MatrixId = _dataFixture.Matrices[1].MatrixId,
                IncludeAggregatedScores = true,
                IncludeAggregatedWeights = true,
                IncludeIndWeightedScores = true,
                IncludeRatings = true,
                GroupBy = ComparativeGroupEnum.PeerGroup,
            };

            //Act
        
            var result1 = _sutClient.PostAsync(_sutLink, options1, JsonMediaTypeFormatter);
            result1.Result.EnsureSuccessStatusCode();
            var esgRatingsDto1 = result1.Result.Content.ReadAsAsync<ESGRatingsDto>(JsonMediaTypeFormatter.Yield());

            var EIndex = GetThemeIndex(esgRatingsDto1.Result, "E");
            var SIndex = GetThemeIndex(esgRatingsDto1.Result, "S");
            var GIndex = GetThemeIndex(esgRatingsDto1.Result, "G");


            var firstResult = esgRatingsDto1.Result.Ratings.Select(x => new
             ESGData(x.CompanyId,
                x.ClustersWeights[EIndex],
                x.ClustersWeights[SIndex],
                x.ClustersWeights[GIndex])
            ).OrderBy(x => x.CompanyId).ToList();


            var result2 = _sutClient.PostAsync(_sutLink, options2, JsonMediaTypeFormatter);
            result2.Result.EnsureSuccessStatusCode();
            var esgRatingsDto2 = result2.Result.Content.ReadAsAsync<ESGRatingsDto>(JsonMediaTypeFormatter.Yield());

            _output.WriteLine(firstResult.Dump());

            //_output.WriteLine(secondResult.Dump());

            var exprected = _dataFixture.Matrices[0].CompaniesWeights.Select(
                x => new ESGData
               (
                    x.CompanyId,
                    x.IndicatorsData.Where(i => i.Code.Contains("E")).Sum(i => i.Value),
                    x.IndicatorsData.Where(i => i.Code.Contains("S")).Sum(i => i.Value),
                    x.IndicatorsData.Where(i => i.Code.Contains("G")).Sum(i => i.Value)
                )).OrderBy(x => x.CompanyId).ToList();

            _output.WriteLine(exprected.Dump());
            //Assert

            Assert.Equal(exprected.Dump(), firstResult.Dump());
        }


        [Fact]
        public void ESGComputeController_Post_Should_Return_Aggregated_Weights_ForMatrixTwo_And_Verify_if_Correct()
        {
            //Arrange

            var options2 = new ESGRatingsOptionsDto()
            {
                RefUnivId = _dataFixture.UniverseId,
                MatrixId = _dataFixture.Matrices[1].MatrixId,
                IncludeAggregatedScores = true,
                IncludeAggregatedWeights = true,
                IncludeIndWeightedScores = true,
                IncludeRatings = true,
                GroupBy = ComparativeGroupEnum.PeerGroup,
            };

            //Act

       

            var result2 = _sutClient.PostAsync(_sutLink, options2, JsonMediaTypeFormatter);
            result2.Result.EnsureSuccessStatusCode();
            var esgRatingsDto2 = result2.Result.Content.ReadAsAsync<ESGRatingsDto>(JsonMediaTypeFormatter.Yield());

            var EIndex = GetThemeIndex(esgRatingsDto2.Result, "E");
            var SIndex = GetThemeIndex(esgRatingsDto2.Result, "S");
            var GIndex = GetThemeIndex(esgRatingsDto2.Result, "G");


            var firstResult = esgRatingsDto2.Result.Ratings.Select(x => new
             ESGData(x.CompanyId,
                x.ClustersWeights[EIndex],
                x.ClustersWeights[SIndex],
                x.ClustersWeights[GIndex])
            ).OrderBy(x => x.CompanyId).ToList();


            _output.WriteLine(firstResult.Dump());


            var exprected = _dataFixture.Matrices[1].CompaniesWeights.Select(
                x => new ESGData
               (
                    x.CompanyId,
                    x.IndicatorsData.Where(i => i.Code.Contains("E")).Sum(i => i.Value),
                    x.IndicatorsData.Where(i => i.Code.Contains("S")).Sum(i => i.Value),
                    x.IndicatorsData.Where(i => i.Code.Contains("G")).Sum(i => i.Value)
                )).OrderBy(x => x.CompanyId).ToList();

            _output.WriteLine(exprected.Dump());
            //Assert

            Assert.Equal(exprected.Dump(), firstResult.Dump());
        }

        private static int GetThemeIndex(ESGRatingsDto data, string themeName)
        {
            if (data == null || data.IndicatorsGroups == null)
            {
                return -1;
            }

            var cluster = data.IndicatorsGroups.Themes.FirstOrDefault(i => String.Compare(i.Name, themeName, StringComparison.OrdinalIgnoreCase) == 0);
            if (cluster != null)
                return cluster.Id;

            return -1;
        }
    }


    public class ESGClientComputingRankingValidationTest : Disposable, IClassFixture<RankingDataFixture>
    {
        private static readonly string _sutLink = "http://localhost:10280/esgcomputingserv/api/v1/esgcompute";

        private static readonly JsonMediaTypeFormatter JsonMediaTypeFormatter = new JsonMediaTypeFormatter
        {
            SerializerSettings = { ContractResolver = new CamelCasePropertyNamesContractResolver() }
        };

        private readonly RankingDataFixture _dataFixture;
        private readonly ITestOutputHelper _output;
        private readonly HttpClient _sutClient;
        private bool _disposed;



        public ESGClientComputingRankingValidationTest(ITestOutputHelper output, RankingDataFixture fixture)
        {
            _output = output;
            _sutClient = new HttpClient();
            _dataFixture = fixture;
        }

        ~ESGClientComputingRankingValidationTest()
        {
            Dispose(false);
        }


        [Fact]
        public void ESGComputeController_Post_Should_Return_EqualRanks_For_C6_And_C7_Theme_Score_Same_Universe_1()
        {
            //Arrange

            var options1 = new ESGRatingsOptionsDto()
            {
                RefUnivId = _dataFixture.ReferenceUniverses[0].Id,
                MatrixId = _dataFixture.Matrices[0].MatrixId,
                IncludeAggregatedScores = true,
                IncludeAggregatedWeights = false,
                IncludeIndWeightedScores = false,
                IncludeRatings = true,
                GroupBy = ComparativeGroupEnum.PeerGroup,
            };

            //Act
            var result1 = _sutClient.PostAsync(_sutLink, options1, JsonMediaTypeFormatter);

            result1.Result.EnsureSuccessStatusCode();

            var esgRatingsDto = result1.Result.Content.ReadAsAsync<ESGRatingsDto>(JsonMediaTypeFormatter.Yield());

            var firstResult = esgRatingsDto.Result.Ratings.SelectMany(x => x.ClustersRatings, (companyId, clusterRatings) => new { companyId.CompanyId, ratings = clusterRatings }).ToList();

             _output.WriteLine(firstResult.Dump());

            var expectedResult = esgRatingsDto.Result.Ratings.SelectMany(x => x.ClustersAggregates, (companyId, clusterRatings) => new { companyId.CompanyId, ratings = clusterRatings }).ToList();

             _output.WriteLine(expectedResult.Dump());


            var rankEC6 = expectedResult.Where(x => x.CompanyId == _dataFixture.Companies[6].Id).ToList()[3].ratings.Rank;

            var rankEC7 = expectedResult.Where(x => x.CompanyId == _dataFixture.Companies[7].Id).ToList()[3].ratings.Rank;

            //Assert

            Assert.Equal(rankEC6, rankEC7);
        }


        [Fact]
        public void ESGComputeController_Post_Should_Return_EqualRanks_For_C7_And_C8_Theme_Score_Same_Universe_1()
        {
            //Arrange

            var options1 = new ESGRatingsOptionsDto()
            {
                RefUnivId = _dataFixture.ReferenceUniverses[0].Id,
                MatrixId = _dataFixture.Matrices[0].MatrixId,
                IncludeAggregatedScores = true,
                IncludeAggregatedWeights = false,
                IncludeIndWeightedScores = false,
                IncludeRatings = true,
                GroupBy = ComparativeGroupEnum.PeerGroup,
            };

            //Act
            var result1 = _sutClient.PostAsync(_sutLink, options1, JsonMediaTypeFormatter);

            result1.Result.EnsureSuccessStatusCode();

            var esgRatingsDto = result1.Result.Content.ReadAsAsync<ESGRatingsDto>(JsonMediaTypeFormatter.Yield());

            var firstResult = esgRatingsDto.Result.Ratings.SelectMany(x => x.ClustersRatings, (companyId, clusterRatings) => new { companyId.CompanyId, ratings = clusterRatings }).ToList();

            _output.WriteLine(firstResult.Dump());

            var expectedResult = esgRatingsDto.Result.Ratings.SelectMany(x => x.ClustersAggregates, (companyId, clusterRatings) => new { companyId.CompanyId, ratings = clusterRatings }).ToList();

            _output.WriteLine(expectedResult.Dump());


            var rankEC6 = expectedResult.Where(x => x.CompanyId == _dataFixture.Companies[7].Id).ToList()[3].ratings.Rank;

            var rankEC7 = expectedResult.Where(x => x.CompanyId == _dataFixture.Companies[8].Id).ToList()[3].ratings.Rank;

            //Assert

            Assert.Equal(rankEC6, rankEC7);
        }


        [Fact]
        public void ESGComputeController_Post_Should_Return_Rank_4_For_Company_9_Universe_1_Theme_Governance()
        {
            //Arrange

            var options1 = new ESGRatingsOptionsDto()
            {
                RefUnivId = _dataFixture.ReferenceUniverses[0].Id,
                MatrixId = _dataFixture.Matrices[0].MatrixId,
                IncludeAggregatedScores = true,
                IncludeAggregatedWeights = false,
                IncludeIndWeightedScores = false,
                IncludeRatings = true,
                GroupBy = ComparativeGroupEnum.PeerGroup,
            };

            //Act
            var result1 = _sutClient.PostAsync(_sutLink, options1, JsonMediaTypeFormatter);

            result1.Result.EnsureSuccessStatusCode();

            var esgRatingsDto = result1.Result.Content.ReadAsAsync<ESGRatingsDto>(JsonMediaTypeFormatter.Yield());

            var ratings = esgRatingsDto.Result.Ratings.Select(x => new { x.CompanyId, ratings = x.ClustersRatings[3],x.GroupId }).ToList();

            _output.WriteLine(ratings.Dump());

            var expectedResult = esgRatingsDto.Result.Ratings.Select(x => new { x.CompanyId, ranking = x.ClustersAggregates[3].Rank }).ToList();

            _output.WriteLine(expectedResult.Dump());

            var actual = expectedResult.FirstOrDefault(x => x.CompanyId == _dataFixture.Companies[9].Id);

            var computedRanking = from o in ratings
                                   orderby o.ratings descending
                                   select new
                                   {
                                       CompanyId = (from n in ratings
                                              where Math.Abs( n.ratings-o.ratings)<=1e-10 && n.CompanyId == o.CompanyId && n.GroupId==o.GroupId
                                               select n.CompanyId).FirstOrDefault(),
                                       Rating = o.ratings,
                                       Position = ratings.Count(s2 => s2.ratings > o.ratings && s2.GroupId==o.GroupId) + 1
                                   };
            _output.WriteLine(computedRanking.Dump());

            var expectedRank = computedRanking.FirstOrDefault(x => x.CompanyId == _dataFixture.Companies[9].Id).Position;
            //Assert

            Assert.Equal(expectedRank, actual.ranking);
        }


        [Fact]
        public void ESGComputeController_Post_Should_Return_Rank_1_For_Company_7_Universe_2_Theme_Governance()
        {
            //Arrange

            var options1 = new ESGRatingsOptionsDto()
            {
                RefUnivId = _dataFixture.ReferenceUniverses[1].Id,
                MatrixId = _dataFixture.Matrices[0].MatrixId,
                IncludeAggregatedScores = true,
                IncludeAggregatedWeights = false,
                IncludeIndWeightedScores = false,
                IncludeRatings = true,
                GroupBy = ComparativeGroupEnum.PeerGroup,
            };

            int companyIndex = 7;

            //Act
            var result1 = _sutClient.PostAsync(_sutLink, options1, JsonMediaTypeFormatter);

            result1.Result.EnsureSuccessStatusCode();

            var esgRatingsDto = result1.Result.Content.ReadAsAsync<ESGRatingsDto>(JsonMediaTypeFormatter.Yield());

            var ratings = esgRatingsDto.Result.Ratings.Select(x => new { x.CompanyId, ratings = x.ClustersRatings[3], x.GroupId }).ToList();

            _output.WriteLine(ratings.Dump());

            var expectedResult = esgRatingsDto.Result.Ratings.Select(x => new { x.CompanyId, ranking = x.ClustersAggregates[3].Rank }).ToList();

            _output.WriteLine(expectedResult.Dump());

            var actual = expectedResult.FirstOrDefault(x => x.CompanyId == _dataFixture.Companies[companyIndex].Id);

            var computedRanking = from o in ratings
                                  orderby o.ratings descending
                                  select new
                                  {
                                      CompanyId = (from n in ratings
                                                   where Math.Abs(n.ratings - o.ratings) <= 1e-10 && n.CompanyId == o.CompanyId && n.GroupId == o.GroupId
                                                   select n.CompanyId).FirstOrDefault(),
                                      Rating = o.ratings,
                                      Position = ratings.Count(s2 => s2.ratings > o.ratings && s2.GroupId == o.GroupId) + 1
                                  };
            _output.WriteLine(computedRanking.Dump());

            var expectedRank = computedRanking.FirstOrDefault(x => x.CompanyId == _dataFixture.Companies[companyIndex].Id).Position;
            //Assert

            Assert.Equal(expectedRank, actual.ranking);
        }


        [Fact]
        public void ESGComputeController_Post_Should_Return_Rank_3_For_Company_9_Universe_2_Theme_Governance()
        {
            //Arrange

            var options1 = new ESGRatingsOptionsDto()
            {
                RefUnivId = _dataFixture.ReferenceUniverses[1].Id,
                MatrixId = _dataFixture.Matrices[0].MatrixId,
                IncludeAggregatedScores = true,
                IncludeAggregatedWeights = false,
                IncludeIndWeightedScores = false,
                IncludeRatings = true,
                GroupBy = ComparativeGroupEnum.PeerGroup,
            };

            int companyIndex = 9;

            //Act
            var result1 = _sutClient.PostAsync(_sutLink, options1, JsonMediaTypeFormatter);

            result1.Result.EnsureSuccessStatusCode();

            var esgRatingsDto = result1.Result.Content.ReadAsAsync<ESGRatingsDto>(JsonMediaTypeFormatter.Yield());

            var ratings = esgRatingsDto.Result.Ratings.Where(x=>x.IsInReferenceUniverse).Select(x => new { x.CompanyId, ratings = x.ClustersRatings[3], x.GroupId }).ToList();

            _output.WriteLine(ratings.Dump());

            var expectedResult = esgRatingsDto.Result.Ratings.Select(x => new { x.CompanyId, ranking = x.ClustersAggregates[3].Rank }).ToList();

            _output.WriteLine(expectedResult.Dump());

            var actual = expectedResult.FirstOrDefault(x => x.CompanyId == _dataFixture.Companies[companyIndex].Id);

            var computedRanking = from o in ratings
                                  orderby o.ratings descending
                                  select new
                                  {
                                      CompanyId = (from n in ratings
                                                   where Math.Abs(n.ratings - o.ratings) <= 1e-10 && n.CompanyId == o.CompanyId && n.GroupId == o.GroupId
                                                   select n.CompanyId).FirstOrDefault(),
                                      Rating = o.ratings,
                                      Position = ratings.Count(s2 => s2.ratings > o.ratings && s2.GroupId == o.GroupId) + 1
                                  };
            _output.WriteLine(computedRanking.Dump());

            var expectedRank = computedRanking.FirstOrDefault(x => x.CompanyId == _dataFixture.Companies[companyIndex].Id).Position;
            //Assert

            _output.WriteLine(string.Format("Expected:{0}, actual{1}",expectedRank,actual.ranking));
            Assert.Equal(expectedRank, actual.ranking);
        }
    }
}